--------------------------------------------------------------------------------
-- PROJET 06-07 - micro java : grammaire LL(3)
-- au format EGG
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------
-- les attributs semantiques
--------------------------------------------------------------------------------
inh tdc : TDC for
	CLASSES, DEFCLASSE, DEFS, DEF, PARFS, PARFSX, PARF, BLOC, INSTS, INST, SIX, F,  E, TX, T, ESX, ERX, ES, ER, AFFX, Q, ARGS, ARGSX ;
inh tdv : TDV for
	PARFS, PARFSX, PARF, BLOC, INSTS, INST, SIX, F, E, TX, T, ESX, ERX, ES, ER, AFFX, Q, ARGS, ARGSX ;
inh classe : INFO_CLASSE for
	DEFS, DEF, PARFS, PARFSX, PARF, BLOC, INSTS, INST, SIX, F, E, TX, T, ESX, ERX, ES, ER, AFFX, Q, ARGS, ARGSX ;
inh meth : INFO_METHODE for
	BLOC, INSTS, INST, SIX ;
syn nom_classe : String for
	EXTENSION ;
syn nom_type : String for
	TYPE, PARF, F, E, OPUN, OPMUL, TX, T, OPADD, ESX, OPREL, ERX, ES, ER, AFFX, Q ;
inh nom_type_inh : String for
	Q ;
inh nom_type_retour : String for
	BLOC, INSTS, INST, SIX, F, E, TX, T, ESX, ERX, ES, ER, AFFX, Q, ARGS, ARGSX ;
inh attribut : INFO_ATTRIBUT for
	Q ;
inh methode : INFO_METHODE for
	Q ;
inh code_attribut : String for
	Q ;
inh code_methode : String for
	Q ;
inh code_inh : String for
	Q ;
inh GenTAM : GenTAM for
	CLASSES, DEFCLASSE, DEFS, DEF, PARFS, PARFSX, PARF, BLOC, INSTS, INST, SIX, F, E, TX, T, ESX, ERX, ES, ER, OPREL, OPADD, OPMUL, OPUN, AFFX, Q, ARGS, ARGSX;
syn code : String for
	CLASSES, DEFCLASSE, DEFS, DEF, BLOC, INSTS, INST, SIX, E, TX, T, ESX, ERX, ES, ER, OPREL, OPADD, OPMUL, OPUN, F, Q, ARGS, ARGSX, AFFX ;
syn signature : Signature for
	ARGS, ARGSX, PARFS, PARFSX ;
syn type_expression : boolean for
	F, AFFX, T, ES, ER, Q;	

--------------------------------------------------------------------------------
-- les terminaux 
--------------------------------------------------------------------------------
space separateur is  "[\r\n\t ]+" ;
space comm       is  "\/\/[^\n]*\n" ;
sugar paro       is  "\(" ;
sugar parf       is  "\)" ;
sugar aco        is  "\{" ;
sugar acf        is  "\}" ;
sugar cro        is  "\[" ;
sugar crf        is  "\]" ;
sugar virg       is  "," ;
sugar pv         is  "\;" ;
sugar pt         is  "\." ;
sugar affect     is  "=" ;
sugar si         is  "if" ;
sugar sinon      is  "else" ;
sugar tantque    is  "while" ;
sugar void       is  "void" ;
sugar int        is  "int" ;
sugar bool       is  "boolean" ;
sugar classe     is  "class" ;
sugar etend      is  "extends" ;
sugar retour     is  "return" ;
sugar nouveau    is  "new" ;
sugar public     is  "public" ;
sugar prive      is  "private" ;
sugar nil        is  "null" ;
sugar inf        is  "\<" ;
sugar infeg      is  "\<=" ;
sugar sup        is  "\>" ;
sugar supeg      is  "\>=" ;
sugar eg         is  "==" ;
sugar neg        is  "\!=" ;
sugar plus       is  "\+" ;
sugar moins      is  "\-" ;
sugar ou         is  "\|\|" ;
sugar mult       is  "\*" ;
sugar div        is  "\/" ;
sugar mod        is  "\%" ; 
sugar et         is  "\&\&" ;
sugar non        is  "\!" ;
sugar vrai       is  "true" ;
sugar faux       is  "false" ;
term  entier     is  "[0-9]+" ;
term  ident      is  "[_A-Za-z][_0-9A-Za-z]*" ;

--------------------------------------------------------------------------------
-- les regles de production
--------------------------------------------------------------------------------
PROGRAMME -> #gen #tdc CLASSES #enregistrer #code ;

global
	tdc : TDC ;
	GenTAM : GenTAM ;

#gen {
do
	GenTAM := new GenTAM("Code") ;
	CLASSES^GenTAM := GenTAM ;
end }

#tdc {
do
	tdc := GenTAM.getTDC() ;
	CLASSES^tdc := tdc ;
end }

#enregistrer {
do
	-- le contenu de la table des classes est enregistre pour etre verifie.
	call tdc.enregistrer("tdc.txt") ;
end }

#code {
do
	call GenTAM.writeFile(GenTAM.genProg(GenTAM.genTV(), CLASSES^code)) ;
end }

--------------------------------------------------------------------------------
CLASSES -> #code ;

#code {
do
	CLASSES^code := "" ;
end }

--------------------------------------------------------------------------------
CLASSES -> DEFCLASSE CLASSES #code ;

#code {
do
	CLASSES^code := DEFCLASSE^code+CLASSES1^code ;
end }

--------------------------------------------------------------------------------
DEFCLASSE -> classe ident EXTENSION aco #tdc DEFS acf #code ;

#tdc {
local
	classe : INFO_CLASSE ;
	classe_parente : INFO_CLASSE ;
	deplacement : Integer ;
do
	classe_parente := DEFCLASSE^tdc.chercher(EXTENSION^nom_classe) ;
	if (EXTENSION^nom_classe.equals("") = false & classe_parente = nil) then
		-- la classe parente demandee n'a pas ete definie.
		error(B_00, EXTENSION^nom_classe, "CLASSE") ;
	end

	classe := DEFCLASSE^tdc.chercher(ident^txt) ;
	if (classe /= nil) then
		-- la classe est deja definie.
		error(B_01, ident^txt, "CLASSE") ;
	end

	deplacement := DEFCLASSE^tdc.getDeplacementSuivant() ;
	if (classe_parente = nil) then
		classe := new INFO_CLASSE(ident^txt, deplacement) ;
	else
		classe := new INFO_CLASSE(ident^txt, deplacement, classe_parente) ;
	end

	call DEFCLASSE^tdc.inserer(classe) ;
	DEFS^classe := classe ;
end }

#code {
do
	DEFCLASSE^code := DEFS^code ;
end }

--------------------------------------------------------------------------------
EXTENSION -> etend ident #nom_classe ;

#nom_classe {
do
	EXTENSION^nom_classe := ident^txt ;
end }

--------------------------------------------------------------------------------
EXTENSION -> #nom_classe ;

#nom_classe {
do
	EXTENSION^nom_classe := "" ;
end }

--------------------------------------------------------------------------------
DEFS -> #code ;

#code {
do
	DEFS^code := "" ;
end }

--------------------------------------------------------------------------------
DEFS -> DEFQUAL DEF DEFS #code ;

#code {
do
	DEFS^code := DEF^code + DEFS1^code ;
end }

--------------------------------------------------------------------------------
DEFQUAL -> public ;

--------------------------------------------------------------------------------
DEFQUAL -> prive ;

--------------------------------------------------------------------------------
DEF -> TYPE ident #tda #typage pv #code ;

#tda {
local
	tda : TDA ;
	attribut : INFO_ATTRIBUT ;
	deplacement : Integer ;
do
	tda := DEF^classe.getTDA() ;

	attribut := tda.chercher(ident^txt) ;
	if (attribut /= nil) then
		error(B_03, ident^txt) ;
	end

	deplacement := tda.getDeplacementSuivant() ;
	attribut := new INFO_ATTRIBUT(ident^txt, TYPE^nom_type, deplacement) ;

	call tda.inserer(attribut) ;
end }

#typage {
local
	classe : INFO_CLASSE ;
do
	classe := DEF^tdc.chercher(TYPE^nom_type) ;
	if (
	 	  ~TYPE^nom_type.equals("int")
		& ~TYPE^nom_type.equals("boolean")
		& classe = nil
	) then
		-- le type n'est pas connu.
		error(B_00, TYPE^nom_type, "TYPE") ;
	end
end }

#code {
do
	DEF^code := "" ;
end }

--------------------------------------------------------------------------------
DEF -> TYPE ident #tdm #typage paro PARFS #signature parf BLOC #code ;

global
	methode : INFO_METHODE ;
#tdm {
local
	tdm : TDM ;
	deplacement : Integer ;
	etiquette : String ;
	sign : Signature ;
	type_retour : String ;
do
	tdm := DEF^classe.getTDM() ;

	etiquette := "_"+DEF^classe.getNom()+"_"+ident^txt ;
	methode := tdm.chercher(ident^txt) ;
	if (methode /= nil & etiquette.equals(methode.getEtiquette())
	) then
		error(B_04, ident^txt) ;
	end
	
	deplacement := tdm.getDeplacementSuivant() ;
	methode := new INFO_METHODE(ident^txt, TYPE^nom_type, deplacement, etiquette) ;

	call tdm.inserer(methode) ;
	PARFS^tdv := methode.getTDV() ;
	BLOC^tdv  := new TDV(methode.getTDV()) ;
	BLOC^nom_type_retour := TYPE^nom_type ;
	BLOC^meth := methode ;
end }

#typage {
local
	classe : INFO_CLASSE ;
do
	classe := DEF^tdc.chercher(TYPE^nom_type) ;
	if (
		  ~TYPE^nom_type.equals("int")
		& ~TYPE^nom_type.equals("boolean")
		& classe = nil
	) then
		error(B_00, TYPE^nom_type, "TYPE") ;
	end
end }

#signature {
local
	tdm : TDM ;
	sign : Signature ;
	type_retour : String ;
do
	tdm := DEF^classe.getTDM() ;

	methode := tdm.chercherLocalement(ident^txt) ;
	if (methode /= nil) then
		sign := methode.getSignature() ;
		type_retour := methode.getNomType() ;
		if (~sign.equals(PARFS^signature) | ~type_retour.equals(TYPE^nom_type)) then
			error(B_04, ident^txt) ;
		end
	end
end }

#code {
do
	DEF^code := DEF^GenTAM.genMeth(methode, DEF^classe, BLOC^code) ;
end }

--------------------------------------------------------------------------------
DEF -> void ident #tdm paro PARFS parf #signature BLOC #code ; 

global
	methode : INFO_METHODE ;
	etiquette : String ;
#tdm {
local
	tdm : TDM ;
	deplacement : Integer ;
	sign : Signature ;
	type_retour : String ;
do
	tdm := DEF^classe.getTDM() ;

	etiquette := "_"+DEF^classe.getNom()+"_"+ident^txt ;
	methode := tdm.chercher(ident^txt) ;
	if (methode /= nil & etiquette.equals(methode.getEtiquette())) then
		error(B_04, ident^txt) ;
	end
	
	deplacement := tdm.getDeplacementSuivant() ;
	methode := new INFO_METHODE(ident^txt, "void", deplacement, etiquette) ;

	call tdm.inserer(methode) ;
	PARFS^tdv := methode.getTDV() ;
	BLOC^tdv  := new TDV(methode.getTDV()) ;
	BLOC^nom_type_retour := "void" ;
	BLOC^meth := methode ;
end }

#signature {
local
	tdm : TDM ;
	sign : Signature ;
	type_retour : String ;
do
	tdm := DEF^classe.getTDM() ;

	methode := tdm.chercherLocalement(ident^txt) ;
	if (methode /= nil) then
		sign := methode.getSignature() ;
		type_retour := methode.getNomType() ;
		if (~sign.equals(PARFS^signature) | ~type_retour.equals("void")) then
			error(B_04, ident^txt) ;
		end
	end
end }

#code {
do
	DEF^code := DEF^GenTAM.genMeth(methode, DEF^classe, BLOC^code) ;
end }

--------------------------------------------------------------------------------
DEF -> ident paro #constructeur PARFS parf BLOC #code ;

global
	methode : INFO_METHODE ;
#constructeur {
local
	etiquette : String ;
do
	methode := DEF^classe.getConstructeur() ;
	if (methode /= nil) then
		-- un constructeur existe deja.
		error(B_01, ident^txt, "CONSTRUCTEUR") ;
	end

	etiquette := "_"+DEF^classe.getNom()+"_"+ident^txt ;
	methode := new INFO_METHODE(ident^txt, "Constructeur!", 0, etiquette) ;

	call DEF^classe.setConstructeur(methode) ;
	PARFS^tdv := methode.getTDV() ;
	BLOC^tdv  := new TDV(methode.getTDV()) ;
	BLOC^nom_type_retour := "" ; -- aucun type ne peut avoir le meme nom !
	BLOC^meth := methode ;
end }

#code {
do
	DEF^code := DEF^GenTAM.genConstructeur(methode, DEF^classe, BLOC^code) ;
end }

--------------------------------------------------------------------------------
-- DEF -> DEFCLASSE ;

--------------------------------------------------------------------------------
TYPE-> int #nom_type ;

#nom_type {
do
	TYPE^nom_type := "int" ;
end }

--------------------------------------------------------------------------------
TYPE-> bool #nom_type ;

#nom_type {
do
	TYPE^nom_type := "boolean" ;
end }

--------------------------------------------------------------------------------
TYPE-> ident #nom_type ;

#nom_type {
do
	TYPE^nom_type := ident^txt ;
end }

--------------------------------------------------------------------------------
PARFS -> #signature ;

#signature {
do
	PARFS^signature := new Signature() ;
end }

--------------------------------------------------------------------------------
PARFS -> PARF PARFSX #signature ;

#signature {
do
	call PARFSX^signature.add(0, PARF^nom_type) ;
	PARFS^signature := PARFSX^signature ;
end }

--------------------------------------------------------------------------------
PARFSX -> #signature ;

#signature {
do
	PARFSX^signature := new Signature() ;
end }

--------------------------------------------------------------------------------
PARFSX -> virg PARF PARFSX #signature ;

#signature {
do
	call PARFSX1^signature.add(0, PARF^nom_type) ;
	PARFSX^signature := PARFSX1^signature ;
end }

--------------------------------------------------------------------------------
PARF -> TYPE ident #tdv #typage #nom_type ;

#tdv {
local
	argument : INFO_VARIABLE ;
	deplacement : int ;
do
	argument := PARF^tdv.chercher(ident^txt) ;
	if (argument /= nil) then
		error(B_01, ident^txt, "VARIABLE") ;
	end

	deplacement := PARF^tdv.getDeplacementNegatifSuivant() ;
	argument := new INFO_VARIABLE(ident^txt, TYPE^nom_type, deplacement) ;

	call PARF^tdv.inserer(argument) ;
end }

#typage {
local
	classe : INFO_CLASSE ;
do
	classe := PARF^tdc.chercher(TYPE^nom_type) ;
	if (
		  ~TYPE^nom_type.equals("int")
		& ~TYPE^nom_type.equals("boolean")
		& classe = nil
	) then
		error(B_00, TYPE^nom_type, "TYPE") ;
	end
end }

#nom_type {
do
	PARF^nom_type := TYPE^nom_type ;
end }

--------------------------------------------------------------------------------
BLOC -> #tdv aco INSTS acf #code ;

global
	tdv : TDV ;

#tdv {
do
	tdv := new TDV(BLOC^tdv) ;
	INSTS^tdv := tdv ;
end }

#code {
do
	BLOC^code := BLOC^GenTAM.genBloc(INSTS^code, tdv.getTaille()) ;
end }

--------------------------------------------------------------------------------
INSTS -> #code ;

#code {
do
	INSTS^code := "" ;
end }

--------------------------------------------------------------------------------
INSTS -> INST INSTS #code ;

#code {
do
	INSTS^code := INST^code + INSTS1^code ;
end }

--------------------------------------------------------------------------------
INST-> TYPE ident #tdv AFFX #typage pv #code ;

global
	variable : INFO_VARIABLE ;

#tdv {
local
	deplacement : Integer ;
do
	variable := INST^tdv.chercherLocalement(ident^txt) ;
	if (variable /= nil) then
		error(B_01, ident^txt, "VARIABLE") ;
	end

	deplacement := INST^tdv.getDeplacementSuivant() ;
	variable := new INFO_VARIABLE(ident^txt, TYPE^nom_type, deplacement) ;

	call INST^tdv.inserer(variable) ;
end }

#typage {
local
	classe : INFO_CLASSE ;
do
	classe := INST^tdc.chercher(TYPE^nom_type) ;
	if (
		  ~TYPE^nom_type.equals("int")
		& ~TYPE^nom_type.equals("boolean")
		& classe = nil
	) then
		error(B_00, TYPE^nom_type, "TYPE") ;
	end

	if (
		  ~AFFX^nom_type.equals("void")
		& ~INST^tdc.isType(AFFX^nom_type, TYPE^nom_type)
	) then
		error(B_02, AFFX^nom_type, TYPE^nom_type) ;
	end
end }

#code {
do
	INST^code := INST^GenTAM.genDecl(TYPE^nom_type, AFFX^code) ;
end }

--------------------------------------------------------------------------------
INST -> E pv #code ;

#code {
do
	INST^code := E^code ;
end }

--------------------------------------------------------------------------------
INST -> BLOC #code ;

#code {
do
	INST^code := BLOC^code ;
end }

--------------------------------------------------------------------------------
INST -> si paro E parf #typage BLOC SIX #code ;

#typage {
do
	if (~E^nom_type.equals("boolean")) then
		error(B_02, E^nom_type, "boolean") ;
	end
end }

#code {
do
	INST^code := INST^GenTAM.genIfThenElse(E^code, BLOC^code, SIX^code) ;
end }

--------------------------------------------------------------------------------
SIX -> sinon BLOC #code ;

#code {
do
	SIX^code := BLOC^code;
end }

--------------------------------------------------------------------------------
SIX -> #code ;

#code {
do
	SIX^code := "" ;
end }

--------------------------------------------------------------------------------
INST -> retour E #typage pv #code ;

#typage {
do
	if (~INST^nom_type_retour.equals(E^nom_type)) then
		error(B_02, E^nom_type, INST^nom_type_retour) ;
	end
end }

#code {
do
	INST^code := INST^GenTAM.genRetour(E^code, INST^meth) ;
end }

--------------------------------------------------------------------------------
INST -> tantque paro E parf #typage BLOC #code ;

#typage {
do
	if (~E^nom_type.equals("boolean")) then
		error(B_02, E^nom_type, "boolean") ;
	end
end }

#code {
do
	INST^code := INST^GenTAM.genWhile(E^code, BLOC^code) ;
end }

--------------------------------------------------------------------------------
E -> ER AFFX #nom_type #code ;

#nom_type {
do
	if (
		  ~AFFX^nom_type.equals("void")
		& ~E^tdc.isType(AFFX^nom_type, ER^nom_type)
	) then
		error(B_02, AFFX^nom_type, ER^nom_type) ;
	end

	E^nom_type := ER^nom_type ;
end }

#code {
do
	E^code := E^GenTAM.genAffectation(ER^code, AFFX^code,ER^type_expression, AFFX^type_expression) ;
end }


--------------------------------------------------------------------------------
AFFX -> affect ER #nom_type #type_expression #code ;

#nom_type {
do
	AFFX^nom_type := ER^nom_type ;
end }

#type_expression {
do
	AFFX^type_expression := ER^type_expression;
end}

#code {
do
	AFFX^code := ER^code ;
end }

--------------------------------------------------------------------------------
AFFX -> #nom_type #type_expression #code;

#nom_type {
do
	-- AFFX est ... sans type ...
	AFFX^nom_type := "void" ;
end }

#type_expression{
do
 AFFX^type_expression := false;
end }

#code {
do
	AFFX^code := "" ;
end }

--------------------------------------------------------------------------------
ER -> ES ERX #nom_type #code #type_expression;

#nom_type {
do
	if (
		  ~ERX^nom_type.equals("void")
		& ~ES^nom_type.equals(ERX^nom_type)
	) then
		error(B_02, ERX^nom_type, ES^nom_type) ;
	end

	if (ERX^nom_type.equals("void")) then
		ER^nom_type := ES^nom_type ;
	else
		ER^nom_type := "boolean" ;
	end
end }

#code {
do
	ER^code := ES^code+ERX^code ;
end }

#type_expression {
do
	if(ERX^code.equals("")) then
		ER^type_expression:= true;
		ER^code := ES^code+ERX^code ;
	else
		ER^type_expression := ES^type_expression;
		if(ES^type_expression) then
			ER^code := ES^code+"LOADI (1)\n"+ERX^code ;
		else
			ER^code := ES^code+ERX^code ;
		end
	end
end }

--------------------------------------------------------------------------------
ES -> T ESX #nom_type #code;

#nom_type {
do
	if (
		  ~ESX^nom_type.equals("void")
		& ~T^nom_type.equals(ESX^nom_type)
	) then
		error(B_02, ESX^nom_type, T^nom_type) ;
	end

	ES^nom_type := T^nom_type ;
end }


#code {
do
	if(ESX^code.equals("")) then
		ES^type_expression:= true;
		ES^code := T^code+ESX^code ;
	else
		ES^type_expression := T^type_expression;
		if(T^type_expression) then
			ES^code := T^code+"LOADI (1)\n"+ESX^code ;
		else
			ES^code := T^code+ESX^code ;
		end
	end
end }

--------------------------------------------------------------------------------
ERX -> OPREL ES #nom_type #code ;

#nom_type {
do
	if (
		  ~OPREL^nom_type.equals("void")
		& ~OPREL^nom_type.equals(ES^nom_type)
	) then
		error(B_02, ES^nom_type, OPREL^nom_type) ;
	end

	ERX^nom_type := ES^nom_type ;
end }

#code {
do
	ERX^code := ES^code+OPREL^code ;
end }

--------------------------------------------------------------------------------
ERX -> #nom_type #code ;

#nom_type {
do
	-- ERX est ... sans type ...
	ERX^nom_type := "void" ;
end }

#code {
do
	ERX^code := "" ;
end }

--------------------------------------------------------------------------------
OPREL -> inf #nom_type #code ;

#nom_type {
do
	OPREL^nom_type := "int" ;
end }

#code {
do
	OPREL^code := OPREL^GenTAM.genIntTestLss() ;
end }

--------------------------------------------------------------------------------
OPREL -> infeg #nom_type #code ;

#nom_type {
do
	OPREL^nom_type := "int" ;
end }

#code {
do
	OPREL^code := OPREL^GenTAM.genIntTestLEq() ;
end }

--------------------------------------------------------------------------------
OPREL -> sup #nom_type #code ;

#nom_type {
do
	OPREL^nom_type := "int" ;
end }

#code {
do
	OPREL^code := OPREL^GenTAM.genIntTestGtr() ;
end }

--------------------------------------------------------------------------------
OPREL -> supeg #nom_type #code ;

#nom_type {
do
	OPREL^nom_type := "int" ;
end }

#code {
do
	OPREL^code := OPREL^GenTAM.genIntTestGEq() ;
end }

--------------------------------------------------------------------------------
OPREL -> eg #nom_type #code ;

#nom_type {
do
	-- OPREL a pour type ce qui le suit !
	OPREL^nom_type := "void" ;
end }

#code {
do
	OPREL^code := OPREL^GenTAM.genIntTestEq() ;
end }

--------------------------------------------------------------------------------
OPREL -> neg #nom_type #code ;

#nom_type {
do
	-- OPREL a pour type ce qui le suit !
	OPREL^nom_type := "void" ;
end }

#code {
do
	OPREL^code := OPREL^GenTAM.genIntTestNEq() ;
end }

--------------------------------------------------------------------------------
ESX -> OPADD T ESX #nom_type #code ;

#nom_type {
do
	if (~OPADD^nom_type.equals(T^nom_type)) then
		error(B_02, T^nom_type, OPADD^nom_type) ;
	end

	if (
		  ~ESX1^nom_type.equals("void")
		& ~T^nom_type.equals(ESX1^nom_type)
	) then
		error(B_02, ESX1^nom_type, T^nom_type) ;
	end

	ESX^nom_type := T^nom_type ;
end }

#code {
do
	ESX^code := T^code+ESX1^code+OPADD^code ;
end }

--------------------------------------------------------------------------------
ESX -> #nom_type #code ;

#nom_type {
do
	-- ESX est ... sans type ...
	ESX^nom_type := "void" ;
end }

#code {
do
	ESX^code := "" ;
end }

--------------------------------------------------------------------------------
OPADD -> plus #nom_type #code ;

#nom_type {
do
	OPADD^nom_type := "int" ;
end }

#code {
do
	OPADD^code := OPADD^GenTAM.genIntAdd() ;
end }

--------------------------------------------------------------------------------
OPADD -> moins #nom_type #code ;

#nom_type {
do
	OPADD^nom_type := "int" ;
end }

#code {
do
	OPADD^code := OPADD^GenTAM.genIntSub() ;
end }

--------------------------------------------------------------------------------
OPADD -> ou #nom_type #code ;

#nom_type {
do
	OPADD^nom_type := "boolean" ;
end }

#code {
do
	OPADD^code := OPADD^GenTAM.genBoolOr() ;
end }

--------------------------------------------------------------------------------
T -> F TX #nom_type #type_expression #code ;

#nom_type {
do
	if (
		  ~TX^nom_type.equals("void")
		& ~F^nom_type.equals(TX^nom_type)
	) then
		error(B_02, TX^nom_type, F^nom_type) ;
	end

	T^nom_type := F^nom_type ;
end }

#code {
local
	s : String ;
do
	s := "" ;
	if (F^type_expression & ~TX^code.equals("")) then
		s := "LOADI (1)\n";
	end
	T^code := F^code+s+TX^code ;
end }
#type_expression {
do
	if(TX^code.equals("")) then
		T^type_expression := true;
	else
		T^type_expression := F^type_expression;
	end
end }
--------------------------------------------------------------------------------
TX -> OPMUL F TX #nom_type #code ;

#nom_type {
do
	if (~OPMUL^nom_type.equals(F^nom_type)) then
		error(B_02, F^nom_type, OPMUL^nom_type) ;
	end

	if (
		  ~TX1^nom_type.equals("void")
		& ~F^nom_type.equals(TX1^nom_type)
	) then
		error(B_02, TX1^nom_type, F^nom_type) ;
	end

	TX^nom_type := F^nom_type ;
end }

#code {
local
	s: String ;
do
	s := "" ;
	if (F^type_expression) then
		s := "LOADI (1)\n";
	end
	TX^code := F^code+s+TX1^code+OPMUL^code ;
end }

--------------------------------------------------------------------------------
TX -> #nom_type #code ;

#nom_type {
do
	-- TX est ... sans type ...
	TX^nom_type := "void" ;
end }

#code {
do
	TX^code := "" ;
end }

--------------------------------------------------------------------------------
OPMUL -> mult #nom_type #code ;

#nom_type {
do
	OPMUL^nom_type := "int" ;
end }

#code {
do
	OPMUL^code := OPMUL^GenTAM.genIntMul() ;
end }

--------------------------------------------------------------------------------
OPMUL -> div #nom_type #code ;

#nom_type {
do
	OPMUL^nom_type := "int" ;
end }

#code {
do
	OPMUL^code := OPMUL^GenTAM.genIntDiv() ;
end }

--------------------------------------------------------------------------------
OPMUL -> mod #nom_type #code ;

#nom_type {
do
	OPMUL^nom_type := "int" ;
end }

#code {
do
	OPMUL^code := OPMUL^GenTAM.genIntMod() ;
end }

--------------------------------------------------------------------------------
OPMUL -> et #nom_type #code ;

#nom_type {
do
	OPMUL^nom_type := "boolean" ;
end }

#code {
do
	OPMUL^code := OPMUL^GenTAM.genBoolAnd() ;
end }

--------------------------------------------------------------------------------
F -> entier #nom_type #type_expression #code ;

#nom_type {
do
	F^nom_type := "int" ;
end }

#code {
do
	F^code := F^GenTAM.genEntier(entier^txt);
end }

#type_expression {
do
	F^type_expression:= false;
end }

--------------------------------------------------------------------------------
F -> vrai #nom_type #type_expression #code ;

#nom_type {
do
	F^nom_type := "boolean" ;
end }

#code {
do
	F^code := F^GenTAM.genBool("true") ;
end }

#type_expression {
do
	F^type_expression:= false;
end }

--------------------------------------------------------------------------------
F -> faux #nom_type #type_expression #code ;

#nom_type {
do
	F^nom_type := "boolean" ;
end }

#code {
do
	F^code := F^GenTAM.genBool("false") ;
end }

#type_expression {
do
	F^type_expression:= false;
end }

--------------------------------------------------------------------------------
F -> OPUN F #nom_type #type_expression #code ;

#nom_type {
do
	if (~OPUN^nom_type.equals(F1^nom_type)) then
		error(B_02, F1^nom_type, OPUN^nom_type) ;
	end

	F^nom_type := F1^nom_type ;
end }

#code {
local
	s : String ;
do
	s := "" ;
	if (F1^type_expression) then
		s := "LOADI (1)\n";
	end
	F^code := F1^code+s+OPUN^code;
end }

#type_expression {
do
	F^type_expression:= false;
end }

--------------------------------------------------------------------------------
OPUN -> plus #nom_type #code ;

#nom_type {
do
	OPUN^nom_type := "int" ;
end }

#code {
do
	OPUN^code := "";
end }

--------------------------------------------------------------------------------
OPUN -> moins #nom_type #code ;

#nom_type {
do
	OPUN^nom_type := "int" ;
end }

#code {
do
	OPUN^code := "";
end }

--------------------------------------------------------------------------------
OPUN -> non #nom_type #code ;

#nom_type {
do
	OPUN^nom_type := "boolean" ;
end }

#code {
do
	OPUN^code := OPUN^GenTAM.genIntNeg();
end }

--------------------------------------------------------------------------------
-- F -> nil ; -- TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

--------------------------------------------------------------------------------
F -> paro E parf #nom_type #type_expression #code ;

#nom_type {
do
	-- F prend le type de l'expression parenthesee.
	F^nom_type := E^nom_type ;
end }

#code {
do
	F^code := E^code ;
end }

#type_expression {
do
	F^type_expression:= false;
end }

--------------------------------------------------------------------------------
F -> nouveau TYPE paro ARGS parf #nom_type #type_expression #code;

#nom_type {
do
	-- F prend le type de l'instance creee.
	F^nom_type := TYPE^nom_type ;
end }

#code {
do
	F^code := F^GenTAM.genAppelConstr(TYPE^nom_type, ARGS^code);
end }

#type_expression {
do
	F^type_expression:= true;
end }
--------------------------------------------------------------------------------
F -> ident #definition #nom_type_inh #code_inh Q #nom_type #code #type_expression;

global
	tdm : TDM ;
	tda : TDA ;
	attribut : INFO_ATTRIBUT ;
	variable : INFO_VARIABLE ;
	methode  : INFO_METHODE ;

#definition {
do
	tda := F^classe.getTDA() ;
	tdm := F^classe.getTDM() ;
	
	attribut := tda.chercher(ident^txt) ;
	variable := F^tdv.chercher(ident^txt) ;
	methode  := tdm.chercher(ident^txt) ;

	if (variable = nil & attribut = nil & methode = nil) then
		error(B_00, ident^txt, "IDENT") ;
	end
end }

#nom_type_inh {
do
	Q^attribut := nil ;
	Q^methode  := methode ;
	Q^nom_type_inh := "null" ;
	
	if (attribut /= nil) then
		Q^attribut := attribut ;
		Q^nom_type_inh := attribut.getNomType() ;
	end
	if (variable /= nil) then
		Q^attribut := variable.toAttribut() ;
		Q^nom_type_inh := variable.getNomType() ;
	end
end }

#code_inh {
do
	Q^code_inh := "LOAD (1) -1[LB]\n";
	Q^code_methode := "" ;
	Q^code_attribut := "" ;
	if (attribut /= nil) then
		Q^code_attribut := F^GenTAM.genAppelAttribut(attribut) ;
	end
	if (variable /= nil) then
		Q^code_attribut := F^GenTAM.genAppelVariable(variable) ;
	end
end }

#nom_type {
do
	F^nom_type := Q^nom_type ;
end }

#code {
do
	F^code := Q^code; 
end
}
#type_expression {
do
	F^type_expression := Q^type_expression;
end }
--------------------------------------------------------------------------------
Q -> #nom_type #code ;

#nom_type {
do
	Q^nom_type := Q^nom_type_inh ;
end }

#code {
do
		
	if (Q^code_attribut.equals("")) then
		Q^code := Q^code_inh + Q^code_methode; 
		Q^type_expression := false;
	else
		Q^code := Q^code_inh + Q^code_attribut; 
		Q^type_expression := true;
	end
end }



--------------------------------------------------------------------------------
Q -> pt ident #init #nom_type_inh #code_inh Q #nom_type #code #type_expression;

global
	classe : INFO_CLASSE ;
	tda : TDA ;
	attribut : INFO_ATTRIBUT ;
	tdm : TDM ;
	methode : INFO_METHODE ;
#init {
do
	-- on cherche la classe liee au type herite
	classe := Q^tdc.chercher(Q^nom_type_inh) ;
	if (classe = nil) then
		error(B_00, Q^nom_type_inh, "TYPE?") ;
	end
	
	tda := classe.getTDA() ;
	attribut := tda.chercher(ident^txt) ;
	
	tdm := classe.getTDM() ;
	methode  := tdm.chercher(ident^txt) ;
end }

#nom_type_inh {
do	
	Q1^attribut := tda.chercher(ident^txt) ;
	Q1^methode  := tdm.chercher(ident^txt) ;
	
	if (attribut = nil) then
		Q1^nom_type_inh := "null" ;
	else
		Q1^nom_type_inh := attribut.getNomType() ;
	end
end }

#code_inh {
do	
	if (Q^code_attribut.equals("")) then
		Q1^code_inh := Q^code_inh + Q^code_methode ; 
	else
		Q1^code_inh := Q^code_inh + Q^code_attribut + "LOADI (1)\n" ; 
	end
	Q1^code_methode := "" ;
	if (attribut = nil) then
		Q1^code_attribut := "" ;
	else
		Q1^code_attribut  := Q^GenTAM.genAppelAttribut(attribut) ;
	end
end }

#nom_type {
do
	Q^nom_type := Q1^nom_type ;
end }

#code {
do
	Q^code := Q1^code; 
end
}

#type_expression {
do
	Q^type_expression := Q1^type_expression;
end }

--------------------------------------------------------------------------------
Q -> paro ARGS parf #nom_type_inh #code_inh Q #nom_type #type_expression #code;

#nom_type_inh {
local
	sign: Signature;
do
	if (Q^methode = nil) then
		error(B_00, "(un ident qu'on ne peut pas recuperer)", "METHODE") ;
	end
	sign := Q^methode.getSignature();
	if (~sign.equals(ARGS^signature)) then
		error(B_05, "(un ident qu'on ne peut pas recuperer)") ;
	end
	
	Q1^nom_type_inh := Q^methode.getNomType() ;
end }

#code_inh {
do
	Q1^code_attribut := "";
	Q1^code_methode := Q^GenTAM.genAppelMethode(Q^methode,ARGS^code);
end }

#nom_type {
do
	Q^nom_type := Q1^nom_type ;
end }

#code {
do
	Q^code := Q1^code; 
end
}

#type_expression {
do
	Q^type_expression := Q1^type_expression;
end }

--------------------------------------------------------------------------------
ARGS -> E ARGSX #signature #code ;

#code {
do
	ARGS^code := ARGSX^code + E^code ;
end }

#signature {
do
	call ARGSX^signature.add(0, E^nom_type) ;
	ARGS^signature := ARGSX^signature ;
end }

--------------------------------------------------------------------------------
ARGS -> #signature #code ;

#code {
do
	ARGS^code := "" ;
end }

#signature {
do
	ARGS^signature := new Signature() ;
end }

--------------------------------------------------------------------------------
ARGSX -> virg E ARGSX #signature #code ;

#code {
do
	ARGSX^code := ARGSX1^code + E^code;
end }

#signature {
do
	call ARGSX1^signature.add(0, E^nom_type) ;
	ARGSX^signature := ARGSX1^signature ;
end }

--------------------------------------------------------------------------------
ARGSX -> #signature #code ;

#code {
do
	ARGSX^code := "";
end }

#signature {
do
	ARGSX^signature := new Signature() ;
end }

--------------------------------------------------------------------------------
-- messages obligatoires
--------------------------------------------------------------------------------
S_00, "Symbole inattendu ^1 au lieu de ^2.", 2 ;
S_01, "Fin de source attendue pres de ^1.", 1 ;
S_02, "Symbole inattendu ^1.", 1 ;

--------------------------------------------------------------------------------
-- messages specifiques
--------------------------------------------------------------------------------
B_00, "Le symbole ^1 (^2) n'est pas defini.", 2 ;
B_01, "Le symbole ^1 (^2) est deja defini.", 2 ;
B_02, "Conversion du type ^1 en ^2 impossible.", 2 ;
B_03, "La redefinition de l'attribut ^1 n'est pas autorisee.", 1 ;
B_04, "La surdefinition de la methode ^1 n'est pas autorisee.", 1 ;
B_05, "Mauvais arguments/types d'arguments transmis a la methode ^1", 1 ;

end
